/**
 * datagrid - jQuery xui
 *
 * Licensed under the Apache v2
 *
 * Copyright 2015 xjb [ beymy.en@gmail.com ]
 *
 * 依赖
 *	linkbutton
 *	pagination
 */
(function($) {
	
	function initDom(target) {
		var state = $.data(target, 'datagrid');
		var t = $(target).addClass('datagrid-table');
		$('>thead>tr', t).addClass('datagrid-header-row').find('th').each(function(i, domEle){
			var thOpts = $.parser.parseOptions(domEle);
			var jq = $(domEle);
			if(thOpts.rownumber) {
				jq.addClass('datagrid-header-rownumber');
			} else if(thOpts.checkbox) {
				jq.addClass('datagrid-td-check').html('<div class="datagrid-header-check"><input type="checkbox"></div>');
			}
		});
		
		var dg = $('<div class="datagrid">'
		+ '<div class="datagrid-header"></div>'
		+ '<div class="datagrid-body">'
		+ '<div class="datagrid-view"></div>'
		+ '</div>'
		+ '</div>');
		state.datagrid = dg;
		
		var title = t.attr('title');
		if(title) {
			dg.children('.datagrid-header').html(title);
		} else {
			dg.children('.datagrid-header').remove();
		}
		
		//宽高处理
		var width = t._css('width');
		var height = t._css('height');
		
		t.after(dg).css({
			width: '',
			height: ''
		});
		
		$('>.datagrid-body>.datagrid-view', dg).append(t).css({
			height: height
		});
		
		dg.css({
			width: width
		});
	}
 
    function wrapGrid(target) {
    	var state = $.data(target, 'datagrid');
    	var datagrid = state.datagrid;
    	var table = $('.datagrid-table', datagrid);
    	state.table = table;
    	
        var columns = getColumns($('thead', table));

        function getColumns(thead) {
            var columns = [];
            $('tr', thead).each(function() {
                var cols = [];
                $('th', this).each(function() {
                    var th = $(this);

                    var col = $.extend({
                        title: th.html()
                    }, $.parser.parseOptions(this, [
                        'align', 'width', {
                            rowspan: 'number',
                            colspan: 'number'
                        }
                    ]));

                    cols.push(col);
                });
                columns.push(cols);
            });

            return columns;
        }

        return {
            columns: columns
        };
    }
 
    function buildBody(target, rows) {
    	var state = $.data(target, 'datagrid');
        var opts = state.options;
        var pagination = opts.pagination;
        var fields = getColumnFields(opts.columns);
        
        var body = [];
        for (var i = 0; i < rows.length; i++) {
            var row = rows[i];
            if (i % 2 && opts.striped) {
                body.push('<tr class="datagrid-row datagrid-row-alt" datagrid-row-index="' + i + '">');
            } else {
                body.push('<tr class="datagrid-row" datagrid-row-index="' + i + '">');
            }

			var rownumber = i + 1;
            if (pagination) {
                rownumber += (opts.pageNumber - 1) * opts.pageSize;
            }
            
            for (var j = 0; j < fields.length; j++) {
                var field = fields[j];
                var col = getColumnOption(opts.columns, field);
                if (col) {
                	
                	if(col.rownumber) {
                		body.push('<td class="datagrid-td-rownumber">');
                	} else if (col.checkbox) {
                		body.push('<td class="datagrid-td-check">');
                	} else {
                    	body.push('<td class="datagrid-cell" field="' + field + '">');
                	}
					
					if (col.rownumber) {
                        body.push('<div class="datagrid-cell-rownumber">'+rownumber+'</div>');
                    } else if (col.checkbox) {
                        body.push('<div class="datagrid-cell-check"><input type="checkbox"/></div>');
                    } else if (col.formatter) {
                        body.push(col.formatter(row[field], row, i));
                    } else {
                        body.push(row[field]);
                    }
                    body.push('</td>');
                }
            }
            body.push('</tr>');
        }

        state.table.children('tbody').html(body.join(''));
    }

	function buildToolbar(target) {
		var state = $.data(target, 'datagrid');
		var datagrid = state.datagrid;
		var opts = state.options;
		var tool = $('>.datagrid-body>.datagrid-toolbar', datagrid);
		if(opts.toolbar) {
			if(tool.length == 0) {
				$(opts.toolbar).addClass('datagrid-toolbar').prependTo($('>.datagrid-body', datagrid));
			}
		}
        tool.children('.l-btn').linkbutton();
    }

    function buildPagination(target) {
        var state = $.data(target, 'datagrid');
        var datagrid = state.datagrid;
        var opts = state.options;
        var pagination = opts.pagination;
        var pager = $('>.datagrid-body>.datagrid-pager', datagrid);
        state.pager = pager;
        
        if (pagination) {
        	if(pager.length == 0) {
        		pager = $('<div class="datagrid-pager"></div>').appendTo(datagrid.children('.datagrid-body'));
        		state.pager = pager;
        	}
        	
            pager.pagination({
                pageNumber: opts.pageNumber,
                pageSize: opts.pageSize,
                pageList: opts.pageList,
                onSelectPage: function(pageNum, pageSize) {
                    // 保存分页状态
                    opts.pageNumber = pageNum;
                    opts.pageSize = pageSize;
        
                    request(target); // 请求远程数据
                }
            });
        }
    }

    function bindEvents(target) {
    	var state = $.data(target, 'datagrid');
    	var table = state.table;
        var opts = state.options;
        var data = state.data;
        
        //body事件
        $('>tbody>tr>td>div.datagrid-cell-check>input[type="checkbox"]', table).unbind('.datagrid').bind('click.datagrid', function(e) {
            e.stopPropagation();
            
            var rowIndex = $(this).parent().parent().parent().attr('datagrid-row-index');
            var rowData = data.rows[rowIndex];
            
            if ($(this).prop('checked')) {
                opts.onCheck.call(target, rowIndex, rowData);
            } else {
                opts.onUncheck.call(target, rowIndex, rowData);
            }
        });

        $('>tbody>tr', table).unbind('.datagrid').bind('click.datagrid', function() {
            var index = $(this).attr('datagrid-row-index');
            if (!$(this).hasClass('datagrid-row-selected')) {
                selectRow(target, index);
            }

            if (opts.onClickRow) {
                opts.onClickRow.call(this, index, data.rows[index]);
            }
        });

        //header事件
        $('>thead>tr>th>div.datagrid-header-check>input[type="checkbox"]', table).unbind('.datagrid').bind('click.datagrid', function() {
            if ($(this).prop('checked')) {
                $('>tbody>tr>td>div.datagrid-cell-check>input[type="checkbox"]', table).prop('checked', true);
                opts.onCheckAll.call(target, data.rows);
            } else {
                $('>tbody>tr>td>div.datagrid-cell-check>input[type="checkbox"]', table).prop('checked', false);
                opts.onUncheckAll.call(target, data.rows);
            }
        });
    }

    function getColumnOption(columns, field) {
        if (columns) {
            for (var i = 0; i < columns.length; i++) {
                var cols = columns[i];
                for (var j = 0; j < cols.length; j++) {
                    var col = cols[j];
                    if (col.field == field) {
                        return col;
                    }
                }
            }
        }
        return null;
    }

    function getColumnFields(columns) {
        if (columns.length == 0) return [];

        function getFields(ridx, cidx, count) {
            var fields = [];
            while (fields.length < count) {
                var col = columns[ridx][cidx];
                if (col.colspan && col.colspan > 1) {
                    var ff = getFields(ridx + 1, getSubColIndex(ridx, cidx), col.colspan);
                    fields = fields.concat(ff);
                } else if (col.field) {
                    fields.push(col.field);
                }
                cidx++;
            }

            return fields;
        }

        function getSubColIndex(ridx, cidx) {
            var index = 0;
            for (var i = 0; i < cidx; i++) {
                var colspan = columns[ridx][i].colspan || 1;
                if (colspan > 1) {
                    index += colspan;
                }
            }
            return index;
        }

        var fields = [];
        for (var i = 0; i < columns[0].length; i++) {
            var col = columns[0][i];
            if (col.colspan && col.colspan > 1) {
                var ff = getFields(1, getSubColIndex(0, i), col.colspan);
                fields = fields.concat(ff);
            } else if (col.field) {
                fields.push(col.field);
            }
        }

        return fields;
    }

    function getColumnColspan(columns) {
        var column = columns[0];
        var colspan = 0;
        for (var i = 0; i < column.length; i++) {
            colspan += (column[i].colspan || 1);
        }
        return colspan;
    }

    function loadData(target, data) {
        var state = $.data(target, 'datagrid');
        var opts = state.options;
        var pagination = opts.pagination;
        
        var pager = state.pager;
        
        //数组数据处理
        if ($.isArray(data)) {
            data = {
                rows: data,
                total: data.length
            }
        } else {
            data.total = parseInt(data.total); //防止total是字符串
        }
        buildBody(target, data.rows);
        state.data = data;

		if(pagination) {
	        pager.pagination({
	            total: data.total
	        });
    	}
	        
        bindEvents(target);
        
        if (opts.onLoadSuccess) {
            opts.onLoadSuccess.call(target, data);
        }
    }
    
    function getRowIndex(target, row) {
        var state = $.data(target, 'datagrid');
        var opts = state.options;
        var rows = state.data.rows;
        var i;
        if (typeof row == 'object') {
            for (i = 0; i < rows.length; i++) {
	            if (rows[i] == row) {
	                return i;
	            }
	        }
        } else {
            for (i = 0; i < rows.length; i++) {
                if (rows[i][opts.idField] == row) {
                    return i;
                }
            }
        }
        return -1;
    };

    function getCheckedRows(target) {
        var state = $.data(target, 'datagrid');
        var table = state.table;
        var data = state.data;

        var rows = [];
        $('>tbody>tr>td>div.datagrid-cell-check>input[type="checkbox"]:checked', table).parent().parent().parent().each(function() {
            var index = parseInt($(this).attr('datagrid-row-index'));
            if (data.rows[index]) {
                rows.push(data.rows[index]);
            }
        });
        return rows;
    };

    function getSelectedRows(target) {
        var state = $.data(target, 'datagrid');
        var table = state.table;
        var data = state.data;

        var rows = [];
        $('>tbody>tr.datagrid-row-selected', table).each(function() {
            var index = parseInt($(this).attr('datagrid-row-index'));
            if (data.rows[index]) {
                rows.push(data.rows[index]);
            }
        });
        return rows;
    }

    /**
     * 清除全部选中记录
     */
    function clearSelections(target) {
    	var state = $.data(target, 'datagrid');
        var table = state.table;
        $('>tbody>tr.datagrid-row-selected', table).removeClass('datagrid-row-selected');
        $('>tbody>tr>td>div.datagrid-cell-check>input[type="checkbox"]', table).prop('checked', false);
    }

    /**
     * 根据索引选中记录,索引从这0开始
     */
    function selectRow(target, index) {
    	var state = $.data(target, 'datagrid');
        var table = state.table;
        var opts = state.options;
        var data = state.data;

        var tr = $('>tbody>tr[datagrid-row-index="' + index + '"]', table);
        clearSelections(target);
        tr.addClass('datagrid-row-selected');

        opts.onSelect.call(target, index, data.rows[index]);
    }

    /**
     * 请求远程数据
     */
    function request(target) {
        var state = $.data(target, 'datagrid');
        var opts = state.options;
        var pagination = opts.pagination;
        
        var pager = state.pager;

        if (!opts.url) {
            return false;
        }

        var param = $.extend({}, opts.queryParams);
        if (pagination) {
            $.extend(param, {
                page: opts.pageNumber,
                rows: opts.pageSize
            });
        }

		pager.pagination('loading');
        $.ajax({
            type: opts.method,
            url: opts.url,
            data: $.toJSON(param),
            contentType: 'application/json',
            dataType: 'json',
            success: function(data) {
            	pager.pagination('loaded');
                loadData(target, data);
            }
        });
    }
    
    function insertRow(target, param) {
    	var state = $.data(target, 'datagrid');
    	var opts = state.options;
        var data = state.data;
        var pager = state.pager;
        
        var index = param.index;
        if (index == undefined || index == null || index > data.rows.length) {
            index = data.rows.length;
        }
                
        data.rows.splice(index, 0, param.row);
        data.total += 1;
        
        loadData(target, data);
     };
    
    function deleteRow(target, index) {
        var state = $.data(target, 'datagrid');
        var opts = state.options;
        var data = state.data;
        var pager = state.pager;
        
        data.rows.splice(index,1);
        
        data.total -= 1;
        
        loadData(target, data);
    };
    
    function acceptChanges(target) {
		var state = $.data(target, 'datagrid');
	    var table = state.table;
	    var data = state.data;
	    $('>tbody>tr>td.datagrid-cell', table).find('input,select').each(function() {
	    	var jq = $(this);
	    	var td = jq.closest('td');
	    	var tr = td.closest('tr');
	    	var rowIndex = tr.attr('datagrid-row-index');
	    	var field = jq.attr('field');
	    	if(!field) {
	    		field = td.attr('field');
	    	}
	    	
	    	if(jq.is('input:checkbox')) {
	    		var jqOpts = $.parser.parseOptions(this);
	    		if(jq.is(':checked')) {
	    			data.rows[rowIndex][field] = jqOpts.on;
	    		} else {
	    			data.rows[rowIndex][field] = jqOpts.off;
	    		}
	    	} else {
	    		data.rows[rowIndex][field] = jq.val();
	    	}
	    });
	}

    $.fn.datagrid = function(options, param) {
        if (typeof options == 'string') {
            return $.fn.datagrid.methods[options](this, param);
        }

        options = options || {};

        return this.each(function() {
            var state = $.data(this, 'datagrid');
            var opts;
            if (state) {
                opts = $.extend(state.options, options);
            } else {
                opts = $.extend({}, $.fn.datagrid.defaults, $.fn.datagrid.parseOptions(this), options);

                state = $.data(this, 'datagrid', {
                    options: opts,
                    data: {
                        total: 0,
                        rows: []
                    }
                });
                
                state.datagrid = $(this);
                if(opts.initDom) {
                	initDom(this);
                }
                
                var wrapResult = wrapGrid(this);
                if (!opts.columns) {
                    opts.columns = wrapResult.columns;
                }
            }
			
			buildToolbar(this);
            buildPagination(this);

            if (opts.data) {
                loadData(this, opts.data);
            }

            if (opts.url) {
                request(this);
            }

            bindEvents(this);
        });
    };

    $.fn.datagrid.methods = {
        options: function(jq) {
            return $.data(jq[0], 'datagrid').options;
        },
        reload: function(jq) {
            return jq.each(function() {
                request(this);
            });
        },
        loadData: function(jq, param) {
            return jq.each(function() {
                loadData(this, param);
            });
        },
        getData: function(jq) {
            return $.data(jq[0], 'datagrid').data;
        },
        getRows: function(jq) {
            return $.data(jq[0], 'datagrid').data.rows;
        },
        getRowIndex: function(jq, row) {
            return getRowIndex(jq[0], row);
        },
        getChecked: function(jq) {
            return getCheckedRows(jq[0]);
        },
        getSelected: function(jq) {
            var rows = getSelectedRows(jq[0]);
            return rows.length > 0 ? rows[0] : null;
        },
        clearSelections: function(jq) {
            return jq.each(function() {
                clearSelections(this);
            });
        },
        selectRow: function(jq, param) {
            return jq.each(function() {
                selectRow(this, param);
            });
        },
        insertRow: function(jq, index, row) {
            return jq.each(function() {
                insertRow(this, index, row);
            });
        }, 
        appendRow: function(jq, row) {
            return jq.each(function() {
                insertRow(this, {
                	index: null,
                	row: row
                });
            });
        },        
        deleteRow: function(jq, param) {
            return jq.each(function() {
                deleteRow(this, param);
            });
        },
        acceptChanges: function(jq) {
            return jq.each(function() {
                acceptChanges(this);
            });
        }
    };

    $.fn.datagrid.parseOptions = function(target) {
        return $.parser.parseOptions(target);
    };

    $.fn.datagrid.defaults = {
    	initDom: false,
        columns: null,
        toolbar: null,
        striped: false, //条纹
        method: 'post',
        idField: null,
        url: null,
        loadMsg: '正在处理，请稍待。。。',
        pagination: false,
        pageNumber: 1,
        pageSize: 10,
        pageList: [10, 20, 50, 100],
        queryParams: {},

        onLoadSuccess: function() {},
        onClickRow: function(rowIndex, rowData) {},
        onSelect: function(rowIndex, rowData) {},
        onCheck: function(rowIndex, rowData) {},
        onUncheck: function(rowIndex, rowData) {},
        onCheckAll: function(rows) {},
        onUncheckAll: function(rows) {}
    };
})(jQuery);
